﻿
using CSharpLibs.Annotations;

namespace System.Collections.Generic
{
	[Builtin]
	public sealed class List<T0> : Object, IList<T0>, ICollection<T0>, IEnumerable<T0>, IList, ICollection, IEnumerable
	{
		private int card;
		private T0[] values;

		public List()
		{
			this.card = 0;
			this.values = new T0[4];
		}

		public List(IEnumerable<T0> oc)
		{
			IEnumerator<T0> ev = oc.GetEnumerator();
			while(ev.MoveNext())
				this.Add(ev.Current);
		}

		public List(int initcapacity)
		{
			this.card = 0;
			this.values = new T0[initcapacity];
		}

		public void Add(T0 val)
		{
			int neededcap = this.card + 1;
			if(neededcap >= this.values.Length)
				Array.Resize(ref this.values, neededcap * 2 + 4);

			this.values[this.card] = val;
			this.card++;
		}

		public void AddRange(IEnumerable<T0> oc)
		{
			IEnumerator<T0> ev = oc.GetEnumerator();
			while(ev.MoveNext())
				this.Add(ev.Current);
		}

		public int BinarySearch(T0 value)
		{
			int low = 0;
			int hi = this.card;

			while(low <= hi)
			{
				int num6;
				int num5 = GetMedian(low, hi);

				num6 = Comparer<T0>.DefaultCompare(this.values[num5], value);

				if(num6 == 0)
					return num5;

				if(num6 < 0)
					low = num5 + 1;
				else
					hi = num5 - 1;
			}

			return ~low;
		}

		public int BinarySearch(T0 value, Comparer<T0> compare)
		{
			int low = 0;
			int hi = this.card;

			while(low <= hi)
			{
				int num6;
				int num5 = GetMedian(low, hi);

				num6 = compare.Compare(this.values[num5], value);

				if(num6 == 0)
					return num5;

				if(num6 < 0)
					low = num5 + 1;
				else
					hi = num5 - 1;
			}

			return ~low;
		}

		private static int GetMedian(int low, int hi)
		{ return (low + ((hi - low) >> 1)); }

		public void Clear()
		{
			for(int i = 0; i < this.card; ++i)
				this.values[i] = default(T0);
			this.card = 0; 
		}

		public bool Contains(T0 val)
		{
			for(int i = 0; i < this.card; i++)
			{
				if(EqualityComparer<T0>.DefaultEquals(val, this.values[i]))
					return true;
			}

			return false;
		}

		public void CopyTo(T0[] array)
		{
			for(int i = 0; i < this.card; ++i)
				array[i] = this.values[i];
		}

		public void CopyTo(T0[] array, int arrayIndex)
		{
			for(int i = 0; i < this.card; ++i)
				array[i + arrayIndex] = this.values[i];
		}

		public void CopyTo(int index, T0[] array, int arrayIndex, int count)
		{
			for(int i = 0; i < count; ++i)
				array[i + arrayIndex] = this.values[i];
		}

		public bool Exists(Predicate<T0> match)
		{
			for(int i = 0; i < this.card; i++)
			{
				if(match(this.values[i]))
					return true;
			}

			return false;
		}

		public T0 Find(Predicate<T0> match)
		{
			for(int i = 0; i < this.card; i++)
			{
				if(match(this.values[i]))
					return this.values[i];
			}

			return default(T0);
		}

		public int FindIndex(Predicate<T0> match)
		{
			for(int i = 0; i < this.card; i++)
			{
				if(match(this.values[i]))
					return i;
			}

			return -1;
		}

		public int FindIndex(int startIndex, int count, Predicate<T0> match)
		{
			int num = startIndex + count;
			for(int i = startIndex; i < num; i++)
			{
				if(match(this.values[i]))
					return i;
			}

			return -1;
		}

		public T0 FindLast(Predicate<T0> match)
		{
			for(int i = this.card - 1; i > 0; i--)
			{
				if(match(this.values[i]))
					return this.values[i];
			}

			return default(T0);
		}

		public int FindLastIndex(Predicate<T0> match)
		{
			for(int i = this.card - 1; i > 0; i--)
			{
				if(match(this.values[i]))
					return i;
			}

			return -1;
		}

		public int FindLastIndex(int startIndex, int count, Predicate<T0> match)
		{
			int num = startIndex - count;
			for(int i = startIndex; i > num; i--)
			{
				if(match(this.values[i]))
					return i;
			}

			return -1;
		}

		public void ForEach(Action<T0> action)
		{
			for(int i = 0; i < this.card; i++)
				action(this.values[i]);
		}
		
		public Enumerator GetEnumerator()
		{ return new Enumerator(this); }

		public int IndexOf(T0 item)
		{
			for(int i = 0; i < this.card; ++i)
			{
				if(EqualityComparer<T0>.DefaultEquals(item, this.values[i]))
					return i;
			}

			return -1;
		}

		public int IndexOf(T0 item, int index, int count)
		{
			int end = index + count;
			for(int i = index; i < end; ++i)
			{
				if(EqualityComparer<T0>.DefaultEquals(item, this.values[i]))
					return i;
			}

			return -1;
		}

		public void Insert(int idx, T0 val)
		{
			int neededcap = this.card + 1;
			if(neededcap >= this.values.Length)
				Array.Resize(ref this.values, neededcap * 2 + 4);

			for(int i = this.card; i > idx; --i)
				this.values[i] = this.values[i - 1];

			this.values[idx] = val;
			this.card++;
		}

		public int LastIndexOf(T0 item)
		{
			for(int i = this.card - 1; i >= 0; i--)
			{
				if(EqualityComparer<T0>.DefaultEquals(this.values[i], item))
					return i;
			}

			return -1;
		}

		public int LastIndexOf(T0 item, int index, int count)
		{
			int num = (index - count) + 1;
			for(int i = index; i >= num; i--)
			{
				if(EqualityComparer<T0>.DefaultEquals(this.values[i], item))
					return i;
			}

			return -1;
		}
		
		public bool Remove(T0 val)
		{
			for(int i = 0; i < this.card; ++i)
			{
				if(EqualityComparer<T0>.DefaultEquals(val, this[i]))
				{
					this.RemoveAt(i);
					return true;
				}
			}

			return false;
		}

		public int RemoveAll(Predicate<T0> match)
		{
			int index = 0;
			while((index < this.card) && !match(this.values[index]))
				index++;

			int num2 = index + 1;
			while(num2 < this.card)
			{
				while((num2 < this.card) && match(this.values[num2]))
					num2++;

				if(num2 < this.card)
					this.values[index++] = this.values[num2++];
			}

			int num3 = this.card - index;
			this.card = index;

			for(int i = 0; i < num3; ++i)
				this.values[i + this.card] = default(T0);

			return num3;
		}

		public void RemoveAt(int pos)
		{
			this.card--;
			if(pos < this.card)
			{
				for(int i = pos; pos < this.card; ++i)
					this.values[i] = this.values[i + 1];

				this.values[this.card] = default(T0);
			}
		}

		public void RemoveRange(int pos, int count)
		{
			this.card -= count;
			if(pos < this.card)
			{
				for(int i = pos; pos < this.card; ++i)
					this.values[i] = this.values[i + 1];

				for(int j = this.card; j < this.card + count; ++j)
					this.values[j] = default(T0);
			}
		}

		public void Reverse()
		{
			int num = 0;
			int num2 = this.card;

			while(num < num2)
			{
				T0 obj2 = this.values[num];
				this.values[num] = this.values[num2];
				this.values[num2] = obj2;

				num++;
				num2--;
			}
		}

		public void Sort()
		{
			for(int k = 0; k < gaps.Length; ++k)
			{
				int gap = gaps[k];
				for(int i = gap; i < this.card; i++)
				{
					T0 vtoins = this.values[i];
					int cpos = i;
					while(cpos > 0 && Comparer<T0>.DefaultCompare(vtoins, this.values[cpos - 1]) < 0)
					{
						this.values[cpos] = this.values[cpos - 1];
						cpos = cpos - 1;
					}
					this.values[cpos] = vtoins;
				}
			}
		}

		public void Sort(Comparer<T0> cmp)
		{
			for(int k = 0; k < gaps.Length; ++k)
			{
				int gap = gaps[k];
				for(int i = gap; i < this.card; i++)
				{
					T0 vtoins = this.values[i];
					int cpos = i;
					while(cpos > 0 && cmp.Compare(vtoins, this.values[cpos - 1]) < 0)
					{
						this.values[cpos] = this.values[cpos - 1];
						cpos = cpos - 1;
					}
					this.values[cpos] = vtoins;
				}
			}
		}

		private static int[] gaps;

		static List()
		{
			gaps = new int[8];
			gaps[0] = 701;
			gaps[1] = 301;
			gaps[2] = 132;
			gaps[3] = 57;
			gaps[4] = 23;
			gaps[5] = 10;
			gaps[6] = 4;
			gaps[7] = 1;
		}

		IEnumerator<T0> IEnumerable<T0>.GetEnumerator()
		{ return new Enumerator(this); }

		IEnumerator IEnumerable.GetEnumerator()
		{ return new Enumerator(this); }

		int IList.Add(object item)
		{
			this.Add((T0)item);
			return (this.Count - 1);
		}

		bool IList.Contains(object item)
		{ return (this.Contains((T0)item)); }

		int IList.IndexOf(object item)
		{ return this.IndexOf((T0)item); }

		void IList.Insert(int index, object item)
		{ this.Insert(index, (T0)item); }

		void IList.Remove(object item)
		{ this.Remove((T0)item); }

		public T0[] ToArray()
		{
			T0[] destinationArray = new T0[this.card];
			for(int i = 0; i < this.card; ++i)
				destinationArray[i] = this.values[i];

			return destinationArray;
		}

		public bool TrueForAll(Predicate<T0> match)
		{
			for(int i = 0; i < this.card; i++)
			{
				if(!match(this.values[i]))
					return false;
			}

			return true;
		}

		public int Count
		{ get { return this.card; } }

		public T0 this[int index]
		{
			get { return this.values[index]; }
			set { this.values[index] = value; }
		}

		object IList.this[int index]
		{
			get { return this[index]; }
			set { this.values[index] = (T0)value; }
		}

		[Builtin]
		public struct Enumerator : IEnumerator<T0>, IDisposable, IEnumerator
		{
			private readonly List<T0> entries;
			private int index;
			
			internal Enumerator(List<T0> ev)
			{
				this.entries = ev;
				this.index = -1;
			}

			public void Dispose()
			{ ;}

			public bool MoveNext()
			{
				if(this.index < this.entries.card - 1)
				{
					this.index++;
					return true;
				}
				else
				{
					this.index = this.entries.card;
					return false;
				}
			}

			public T0 Current
			{ get { return this.entries.values[this.index]; } }

			object IEnumerator.Current
			{ get { return this.entries.values[this.index]; } }

			void IEnumerator.Reset()
			{ this.index = -1; }
		}
	}
}

